package com.tuton.javanet.chapter03;

import java.util.LinkedList;

public class Thread02ThreadPool extends ThreadGroup {
	
	private boolean isClose = false;//mark the ThreadPool close or not
	private LinkedList <Runnable> workQueue;//stand for WORK QUEUE
	private static int ThreadPoolID;//ID of this ThreadPool
	private int threadID;//ID of threads in this ThreadPool
	
	public Thread02ThreadPool(int poolSize) {
		super("ThreadPool - " + (ThreadPoolID++));
		super.setDaemon(true);
		workQueue = new LinkedList();
		for(int i = 0; i < poolSize; i++) {
			new WorkThread().start();
		}
		System.out.println(isClose);
	}
	
	public synchronized void execute(Runnable task) {
		
		if(isClose) {
			throw new IllegalStateException();
		}
		
		if(null != task) {
			workQueue.add(task);
System.out.println("the size of workQuue : " + workQueue.size());
			notify();
		}
	}
	
	public synchronized Runnable getTask() throws InterruptedException {
		
		while(0 == workQueue.size()) {
			if(isClose) return null;
			wait();
		}
		
		return workQueue.removeFirst();
	}
	
	public synchronized void close() {
		if(!isClose) {
			isClose = true;
			workQueue.clear();
			interrupt();
		}
	}
	
	public void join() {
		synchronized(this) {
			isClose = true;
			notifyAll();
		}
		//initial a array of threads of the size of active threads
		Thread[] threads = new Thread[activeCount()];
		//get the current threads and put them into the <threads>
		int count = this.enumerate(threads);
		
		for(int i = 0; i < count; i++) {
			try {
				threads[i].join();//wait for the Thread's finish
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	private class WorkThread extends Thread {
		
		public WorkThread(){
			super("WorkThread - " + threadID++);//get a name for this thread
		}
		
		public void run(){
			//while the thread was not interrupted by other threads , do it's job
			while(!isInterrupted()) {
				Runnable task = null;
				
				try{
					task = getTask();
				} catch(InterruptedException ex) {
					ex.printStackTrace();
				}
				
				if(null == task) return; //if the task was null, no need to run it
				  
				try{
					task.run();//run the task
				} catch(Throwable t) {
					t.printStackTrace();
					
				}
			}//#while
		}//#run()
	}//#workThread
	
}
